Skip to content

Add support for perceptual image encoding#3113

Draft
BezBIS wants to merge 1 commit intogetzola:nextfrom
BezBIS:perceptual-image
Draft

Add support for perceptual image encoding#3113
BezBIS wants to merge 1 commit intogetzola:nextfrom
BezBIS:perceptual-image

Conversation

@BezBIS
Copy link

@BezBIS BezBIS commented Feb 24, 2026

IMPORTANT: Please do not create a Pull Request adding a new feature without discussing it first.

The place to discuss new features is the forum: https://zola.discourse.group/
If you want to add a new feature, please open a thread there first in the feature requests section.

Sanity check:

  • Have you checked to ensure there aren't other open Pull Requests for the same update/change?

Code changes

(Delete or ignore this section for documentation changes)

  • Are you doing the PR on the next branch?

If the change is a new feature or adding to/changing an existing one:

  • Have you created/updated the relevant documentation page(s)?

This draft pr adds support for perceptual image compression as a post-processing step as discussed in #1429. To enable this feature, users would add a new section to the config.toml defining glob patterns and compression options:

compress_images = [
    { glob = "**/*.jpg", format = "jpeg", target_ssim: 0.85 }
]

How it works?

As the last stage ofzola build before copying static to the output folder, the static directory is searched for files matching each glob pattern, and perceptual image compression is run on them according to the configured options. Compressed files are then output to the new compressed_files directory, and any older compressed images not found in the build are cleaned out. Finally, all html files in the public directory are scanned for links to raw images, and updated to instead link to the compressed version.

Pros of this approach

  • CPU intensive compression is only run on build, serve should remain quick.
  • Any files in static matching defined globs can be compressed, not just those processed in-template with process_image.

Cons of this approach

  • There is no easy way to change output format on an image by image basis, only via glob. Areas where this may cause problems are when encoding multiple formats of the same source image for use in responsive images.
  • Users would need to change existing calls to process_image to output lossless or high quality level images: perceptual compression needs high quality source images, or perceived quality may actually decrease. This could cause issues when combined with the above (if all images are output as png to preserve maximum quality, there is no way of knowing which are intend to remain as png, or which to be converted to jpeg etc).
  • The final html of the site has to be overwritten to replace paths, as image processing is run after html generation.
  • Many images may be duplicated in the final public folder. E.g. one copy in processed_images and another in compressed_images. This may not be a problem for many users, but could cause issues with larger sites on small hosting plans, or those who upload files via ftp / scp etc.

My thoughts

In my opinion, I think the cons of this approach may outweigh the pros vs adding support for perceptual encoding directly to process_image. Serve will be much faster this way, but the cost is substantial loss of flexibility when it comes to deciding output format on an image by image basis, and large amounts of duplication in the final public folder.

However, I would welcome any discussion and am happy to proceed with this approach if the consensus is it is the better option for users. My current approach is very naive, and there may be a better way of adding this as a post-processing step that fits better with the existing processes etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant